package usw.webserver.entity;

import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;

import org.apache.log4j.Logger;


/**
 *
 *
 */
public class HttpResponse {

	private static Logger log = Logger.getLogger(HttpResponse.class);

	public static final String VERSION = "HTTP/1.0";

	List<String> headers = new ArrayList<String>();

	byte[] body;

	private	String 	webRootPath;
	
	/**
	 * 
	 * @param req
	 * @throws IOException
	 */
	public HttpResponse(HttpRequest req, String webRootPath) throws IOException {

		this.webRootPath = webRootPath;
		
		switch (req.method.getMethod()) 
		{
			case Method.HEAD:
				fillHeaders(new Status(Status.STATUS_200));
				break;
				
			case Method.GET:
				
				try 
				{
					fillHeaders(new Status(Status.STATUS_200));
				
					// Handle Directory
					File file = new File(webRootPath + req.uri);
					if 	(file.isDirectory()) {
						
						headers.add(ContentType.STR_CONTENT_TYPE_HTML);
						StringBuilder result = new StringBuilder("<html><head><title>Index of ");
						result.append(req.uri);
						result.append("</title></head><body><h1>Index of ");
						result.append(req.uri);
						result.append("</h1><hr><pre>");

						// add Parent Directory
						File[] files = file.listFiles();
						for (File subfile : files) {
							result.append(" <a href=\"" + subfile.getPath() + "\">" + subfile.getPath() + "</a>\n");
						}
						
						result.append("<hr></pre></body></html>");
						fillResponse(result.toString());
					} 
					else if (file.exists()) 
					{
						//	Handle Single File
						
						setContentType(req.uri, headers);
						fillResponse(getBytes(file));
					} 
					else 
					{
						log.info("File not found:" + req.uri);
						fillHeaders(new Status(Status.STATUS_404));
						fillResponse(Status.STR_STATUS_404);
					}
				} 
				catch (Exception e) {
				
					log.error("Response Error", e);
					fillHeaders(new Status(Status.STATUS_400));
					fillResponse(Status.STR_STATUS_404);
				}

				break;
				
			case Method.UNRECOGNIZED:
				
				fillHeaders(new Status(Status.STATUS_400));
				fillResponse(Status.STR_STATUS_404);
				break;
				
			default:
				fillHeaders(new Status(Status.STATUS_501));
				fillResponse(Status.STR_STATUS_501);
		}

	}

	/**
	 * 
	 * @param file
	 * @return
	 * @throws IOException
	 */
	private byte[] getBytes(File file) throws IOException {
		
		int length = (int) file.length();
		byte[] array = new byte[length];
		InputStream in = new FileInputStream(file);
		int offset = 0;
		
		while (offset < length) {
			
			int count = in.read(array, offset, (length - offset));
			offset += count;
		}
		
		in.close();
		
		return array;
	}

	/**
	 * Fill Headers
	 * @param status
	 */
	private void fillHeaders(Status status) {
		
		headers.add(HttpResponse.VERSION + " " + status.toString());
		headers.add("Connection: close");
		headers.add("Server: ApacheServer");
	}

	/**
	 * Fill Response with String 
	 * @param response
	 */
	private void fillResponse(String response) {
		
		body = response.getBytes();
	}

	/**
	 * Fill Response with byte[]
	 * @param response
	 */
	private void fillResponse(byte[] response) {
		
		body = response;
	}

	/**
	 * Output 
	 * @param os
	 * @throws IOException
	 */
	public void write(OutputStream os) throws IOException 
	{
		DataOutputStream output = new DataOutputStream(os);
		for (String header : headers) {
			output.writeBytes(header + "\r\n");
		}
		output.writeBytes("\r\n");
	
		if (body != null) {
			output.write(body);
		}
		
		output.writeBytes("\r\n");
		output.flush();
	}

	/**
	 * 
	 * @param uri
	 * @param list
	 */
	private void setContentType(String uri, List<String> list) 
	{
		try 
		{
			String ext = uri.substring(uri.indexOf(".") + 1);
			list.add(ContentType.getContentTypeBySuffix(ext));
		} 
		catch (Exception e) {
			
			log.error("ContentType not found: " + e, e);
		}
	}
}
